#light
// ---------------------------------------------------------------

namespace Langexplr.Abc

open Langexplr.Abc
open System.IO
open System

type JumpLabelReference =
   | UnSolvedReference of int
   | SolvedReference of string
with
   override this.ToString() = 
      match this with
      | UnSolvedReference addr -> sprintf "UnSolvedReference %d" addr
      | SolvedReference label -> sprintf "SolvedReference %s" label
end   


type AbcFileInstruction =
    | ArtificialCodeBranchLabel of string
    | Add        
    | AsType of int
    | AsTypeLate
    | BitAnd
    | BitNot
    | BitOr
    | BitXor
    | Call of int
    | CallMethod of int * int
    | CallProperty of QualifiedName * int
    | CallPropLex of int * int
    | CallPropVoid of QualifiedName * int
    | CallStatic of int * int
    | CallSuper of QualifiedName * int
    | CallSuperVoid of int * int
    | CheckFilter
    | Coerce of int
    | CoerceA
    | CoerceS
    | Construct of int
    | ConstructProp of QualifiedName * int
    | ConstructSuper of int
    | ConvertB
    | ConvertI
    | ConvertD
    | ConvertO
    | ConvertU
    | ConvertS
    | Debug of byte * int * byte * int
    | DebugFile of int
    | DebugLine of int
    | DecLocal of int
    | DecLocalI of int
    | Decrement
    | DecrementI    | DeleteProperty of int
    | Divide
    | Dup
    | DXNs of int
    | DXNslate
    | Equals
    | EscXAttr
    | EscXElem
    | FindProperty of QualifiedName
    | FindPropertyStrict of QualifiedName
    | GetDescendants of int
    | GetGlobalScope
    | GetGlobalSlot of int
    | GetLex of QualifiedName
    | GetLocal of int
    | GetLocal0
    | GetLocal1
    | GetLocal2
    | GetLocal3
    | GetProperty of QualifiedName
    | GetScopeObject of int
    | GetSlot of int
    | GetSuper of int
    | GreaterEquals
    | GreaterThan
    | HasNext
    | HasNext2 of uint32 * uint32
    | IfEq of JumpLabelReference
    | IfFalse of JumpLabelReference
    | IfGe of JumpLabelReference
    | IfGt of JumpLabelReference     
    | IfLe of JumpLabelReference     
    | IfLt of JumpLabelReference 
    | IfNGe of JumpLabelReference      
    | IfNGt of JumpLabelReference    
    | IfNLe of JumpLabelReference
    | IfNLt of JumpLabelReference
    | IfNE of JumpLabelReference
    | IfStrictEq of JumpLabelReference
    | IfStrictNEq of JumpLabelReference
    | IfTrue of JumpLabelReference
    | In
    | IncLocal of int  
    | IncLocalI of int  
    | Increment
    | IncrementI
    | InitProperty of QualifiedName
    | InstanceOf
    | IsType of int
    | IsTypeLate
    | Jump of JumpLabelReference
    | Kill of int
    | Label
    | LessEquals
    | LessThan
    | LookupSwitch of JumpLabelReference * JumpLabelReference array
    | LShift
    | Modulo
    | Multiply
    | MultiplyI
    | Negate
    | NegateI
    | NewActivation
    | NewArray of int
    | NewCatch of int
    | NewClass of QualifiedName
    | NewFunction of int
    | NewObject of int
    | NextName
    | NextValue
    | Nop
    | Not
    | Pop
    | PopScope
    | PushByte of byte
    | PushDouble of double 
    | PushFalse
    | PushInt of int        
    | PushNamespace of int
    | PushNan
    | PushNull
    | PushScope
    | PushShort of int
    | PushString of string
    | PushTrue
    | PushUInt of int
    | PushUndefined
    | PushWith
    | ReturnValue
    | ReturnVoid
    | RShift
    | SetLocal of int
    | SetLocal_0
    | SetLocal_1
    | SetLocal_2
    | SetLocal_3
    | SetGlobalSlot of int
    | SetProperty  of int
    | SetSlot of int
    | SetSuper of int
    | StrictEquals
    | Subtract
    | SubtractI
    | Swap
    | Throw
    | TypeOf
    | URShift
with
   static member ReadFrom(input : BinaryReader,cp:ConstantPoolInfo,classNames : QualifiedName array) : AbcFileInstruction=
      match int(input.ReadByte()) with
         | 0xa0 -> Add
         | 0x86 -> AsType(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x87 -> AsTypeLate
         | 0xa8 -> BitAnd
         | 0x97 -> BitNot
         | 0xa9 -> BitOr  
         | 0xaa -> BitXor 
         | 0x41 -> Call(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x43 -> CallMethod(int(TypeEncodingUtilities.ReadU30Value(input)),int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x46 -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                      CallProperty(name,int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x4c -> CallPropLex(int(TypeEncodingUtilities.ReadU30Value(input)),int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x4f -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                       CallPropVoid(name,int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x44 -> CallStatic(int(TypeEncodingUtilities.ReadU30Value(input)),int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x45 -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                   in
                       CallSuper(name,int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x4e -> CallSuperVoid(int(TypeEncodingUtilities.ReadU30Value(input)),int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x78 -> CheckFilter
         | 0x80 -> Coerce(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x82 -> CoerceA
         | 0x85 -> CoerceS
         | 0x42 -> Construct(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x4a -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                      ConstructProp(name,int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x49 -> ConstructSuper(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x76 -> ConvertB
         | 0x73 -> ConvertI
         | 0x75 -> ConvertD
         | 0x77 -> ConvertO
         | 0x74 -> ConvertU
         | 0x70 -> ConvertS
         | 0xef -> Debug(input.ReadByte(),int(TypeEncodingUtilities.ReadU30Value(input)),input.ReadByte(),int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xf1 -> DebugFile(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xf0 -> DebugLine(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x94 -> DecLocal(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xc3 -> DecLocalI(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x93 -> Decrement
         | 0xc1 -> DecrementI
         | 0x6a -> DeleteProperty(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xa3 -> Divide
         | 0x2a -> Dup
         | 0x06 -> DXNs(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x07 -> DXNslate // Different from spec
         | 0xab -> Equals
         | 0x72 -> EscXAttr
         | 0x71 -> EscXElem
         | 0x5e -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                      FindProperty name
         | 0x5d -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                      FindPropertyStrict name
         | 0x59 -> GetDescendants(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x64 -> GetGlobalScope
         | 0x6e -> GetGlobalSlot(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x60 ->  let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                      GetLex name
         | 0x62 -> GetLocal(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xd0 -> GetLocal0
         | 0xd1 -> GetLocal1
         | 0xd2 -> GetLocal2
         | 0xd3 -> GetLocal3
         | 0x66 -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in GetProperty name
         | 0x65 -> GetScopeObject(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x6c -> GetSlot(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x04 -> GetSuper(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xaf -> GreaterEquals
         | 0xb0 -> GreaterThan // Not in documentation
         | 0x1f -> HasNext
         | 0x32 -> HasNext2(uint32(TypeEncodingUtilities.ReadU30Value(input)),uint32(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x13 -> IfEq <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x12 -> IfFalse <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))                    
         | 0x18 -> IfGe <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x17 -> IfGt <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x16 -> IfLe <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x15 -> IfLt <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x0f -> IfNGe <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x0e -> IfNGt <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x0d -> IfNLe <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x0c -> IfNLt <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x14 -> IfNE <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x19 -> IfStrictEq <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x1a -> IfStrictNEq <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x11 -> IfTrue <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0xb4 -> In
         | 0x92 -> IncLocal(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xc2 -> IncLocalI(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x91 -> Increment
         | 0xc0 -> IncrementI
         | 0x68 -> let name = cp.SolveMultiName(int(TypeEncodingUtilities.ReadU30Value(input)))
                    in
                       InitProperty(name)
         | 0xb1 -> InstanceOf
         | 0xb2 -> IsType(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xb3 -> IsTypeLate
         | 0x10 -> Jump <| UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input))
         | 0x08 -> Kill(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x09 -> Label
         | 0xae -> LessEquals
         | 0xad -> LessThan
         | 0x1b -> let defaultc = UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input)) in
                   let count = int(TypeEncodingUtilities.ReadU30Value(input)) in
                   //printf "en todas %d\n" count
                   LookupSwitch(defaultc,
                                [|for _ in 0 .. count
                                   -> UnSolvedReference(TypeEncodingUtilities.ReadS24Value(input)) |])
         | 0xa5 -> LShift
         | 0xa4 -> Modulo
         | 0xa2 -> Multiply
         | 0xc7 -> MultiplyI
         | 0x90 -> Negate
         | 0xc4 -> NegateI
         | 0x57 -> NewActivation
         | 0x56 -> NewArray(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x5a -> NewCatch(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x58 -> let classInfoEntry = int(TypeEncodingUtilities.ReadU30Value(input)) in                   
                     NewClass(classNames.[classInfoEntry])
         | 0x40 -> NewFunction(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x55 -> NewObject(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x1e -> NextName
         | 0x23 -> NextValue
         | 0x02 -> Nop
         | 0x96 -> Not
         | 0x29 -> Pop
         | 0x1d -> PopScope
         | 0x24 -> PushByte(input.ReadByte())
         | 0x2f ->  let doubleIndex = int(TypeEncodingUtilities.ReadU30Value(input)) 
                    in
                      PushDouble <| cp.GetDouble(doubleIndex)
         | 0x27 -> PushFalse
         | 0x2d -> let intIndex = int(TypeEncodingUtilities.ReadU30Value(input)) 
                    in
                      PushInt <| cp.GetInt(intIndex)
         | 0x31 -> PushNamespace(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x28 -> PushNan
         | 0x20 -> PushNull
         | 0x30 -> PushScope
         | 0x25 -> PushShort(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x2c -> let stringIndex = (int(TypeEncodingUtilities.ReadU30Value(input))) in
                     PushString <| cp.GetString(stringIndex)
         | 0x26 -> PushTrue
         | 0x2e -> PushUInt(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x21 -> PushUndefined
         | 0x1c -> PushWith
         | 0x48 -> ReturnValue
         | 0x47 -> ReturnVoid
         | 0xa6 -> RShift
         | 0x63 -> SetLocal(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xd4 -> SetLocal_0
         | 0xd5 -> SetLocal_1
         | 0xd6 -> SetLocal_2
         | 0xd7 -> SetLocal_3
         | 0x6f -> SetGlobalSlot(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x61 -> SetProperty(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x6d -> SetSlot(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0x05 -> SetSuper(int(TypeEncodingUtilities.ReadU30Value(input)))
         | 0xac -> StrictEquals
         | 0xa1 -> Subtract
         | 0xc6 -> SubtractI
         | 0x2b -> Swap
         | 0x03 -> Throw
         | 0x95 -> TypeOf
         | 0xa7 -> URShift    
         | u -> raise (new System.InvalidOperationException(String.Format("Unknown instruction {0}",u)))
         
   member this.WriteTo(output : BinaryWriter,fileCreator:AbcFileCreator) : unit =
      match this with
         | ArtificialCodeBranchLabel _ -> ()
         | Add -> output.Write(byte(0xa0));
         | AsType typeIndex -> output.Write(byte(0x86));
                               TypeEncodingUtilities.WriteU30Value(uint32(typeIndex),output)
         | AsTypeLate -> output.Write(byte(0x87))                               
         | BitAnd -> output.Write(byte(0xa8))
         | BitNot -> output.Write(byte(0x97))
         | BitOr   -> output.Write(byte(0xa9))
         | BitXor  -> output.Write(byte(0xaa))
         | Call argCount -> 
                output.Write(byte(0x41));
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallMethod(methodIndex,argCount) -> 
                output.Write(byte(0x43));
                TypeEncodingUtilities.WriteU30Value(uint32(methodIndex),output);
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallProperty(propertyName,argCount) -> 
                output.Write(byte(0x46));
                let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName) in                   
                  TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
                  TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallPropLex(methodIndex,argCount)  -> 
                output.Write(byte(0x4c));
                TypeEncodingUtilities.WriteU30Value(uint32(methodIndex),output);
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallPropVoid(name,argCount)  ->  
                output.Write(byte(0x4f));
                let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(name) in                   
                  TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);                
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallStatic(methodIndex,argCount)  -> 
                output.Write(byte(0x44));
                TypeEncodingUtilities.WriteU30Value(uint32(methodIndex),output);
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallSuper(methodName,argCount)  -> 
                output.Write(byte(0x45));
                let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(methodName) in                   
                TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CallSuperVoid(methodIndex,argCount)  -> 
                output.Write(byte(0x4e));                
                TypeEncodingUtilities.WriteU30Value(uint32(methodIndex),output);
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | CheckFilter -> output.Write(byte(0x78));
         | Coerce typeIndex -> 
                output.Write(byte(0x80));
                TypeEncodingUtilities.WriteU30Value(uint32(typeIndex),output)
         | CoerceA -> output.Write(byte(0x82));
         | CoerceS -> output.Write(byte(0x85));
         | Construct argCount -> 
                output.Write(byte(0x42));
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | ConstructProp(propertyName,argCount) -> 
                output.Write(byte(0x4a));
                let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName) in
                TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | ConstructSuper argCount -> 
                output.Write(byte(0x49));
                TypeEncodingUtilities.WriteU30Value(uint32(argCount),output)
         | ConvertB -> output.Write(byte(0x76));
         | ConvertI -> output.Write(byte(0x73));
         | ConvertD -> output.Write(byte(0x75));
         | ConvertO -> output.Write(byte(0x77));
         | ConvertU -> output.Write(byte(0x74));
         | ConvertS -> output.Write(byte(0x70));
         | Debug(debugType,index,reg,extra) -> 
                output.Write(byte(0xef));
                output.Write(byte(debugType));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
                output.Write(byte(reg));
                TypeEncodingUtilities.WriteU30Value(uint32(extra),output);
         | DebugFile(fileIndex) -> 
                output.Write(byte(0xf1));
                TypeEncodingUtilities.WriteU30Value(uint32(fileIndex),output);
         | DebugLine(lineNumber) -> 
                output.Write(byte(0xf0));
                TypeEncodingUtilities.WriteU30Value(uint32(lineNumber),output);
         | DecLocal(index) -> 
                output.Write(byte(0x94));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | DecLocalI(index) -> 
                output.Write(byte(0xc3));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | Decrement -> output.Write(byte(0x93));
         | DecrementI -> output.Write(byte(0xc1));
         | DeleteProperty(index) -> 
                output.Write(byte(0x6a));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | Divide -> output.Write(byte(0xa3));
         | Dup -> output.Write(byte(0x2a));
         | DXNs(index) -> 
                output.Write(byte(0x06));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | DXNslate // Different from spec -> output.Write(byte(0x07));
         | Equals -> output.Write(byte(0xab));
         | EscXAttr -> output.Write(byte(0x72));
         | EscXElem -> output.Write(byte(0x71));
         | FindProperty(propertyName) ->                   
                  output.Write(byte(0x5e));
                  let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName)
                   in
                    TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
         | FindPropertyStrict(propName) -> 
                  output.Write(byte(0x5d));
                  let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propName)
                   in
                    TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
         | GetDescendants(index) -> 
                  output.Write(byte(0x59));
                  TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | GetGlobalScope -> output.Write(byte(0x64));
         | GetGlobalSlot(index) -> 
                  output.Write(byte(0x6e));
                  TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | GetLex(name) -> 
                  output.Write(byte(0x60));
                  let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(name)
                   in
                    TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);

         | GetLocal(index) -> 
                  output.Write(byte(0x62));
                  TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | GetLocal0 -> output.Write(byte(0xd0));
         | GetLocal1 -> output.Write(byte(0xd1));
         | GetLocal2 -> output.Write(byte(0xd2));
         | GetLocal3 -> output.Write(byte(0xd3));
         | GetProperty(propertyName) -> 
                  output.Write(byte(0x66));
                  let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName)
                   in
                  TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
         | GetScopeObject(index) -> 
                  output.Write(byte(0x65));
                  TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | GetSlot(index) -> 
                  output.Write(byte(0x6c));
                  TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | GetSuper(index) -> 
                  output.Write(byte(0x04));
                  TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | GreaterEquals -> output.Write(byte(0xaf));
         | GreaterThan // Not in documentation -> output.Write(byte(0xb0));
         | HasNext -> output.Write(byte(0x1f));
         | HasNext2(objectreg,index) -> 
                 output.Write(byte(0x32));
                 TypeEncodingUtilities.WriteU30Value(uint32(objectreg),output);
                 TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | IfEq(destination) -> 
                 output.Write(byte(0x13));
                 this.WriteBranchDestination(destination,output)
         | IfFalse(destination) -> 
                 output.Write(byte(0x12));
                 this.WriteBranchDestination(destination,output)
         | IfGe(destination) -> 
                 output.Write(byte(0x18));
                 this.WriteBranchDestination(destination,output)
         | IfGt(destination) -> 
                 output.Write(byte(0x17));
                 this.WriteBranchDestination(destination,output)
         | IfLe(destination) -> 
                 output.Write(byte(0x16));
                 this.WriteBranchDestination(destination,output)
         | IfLt(destination) -> 
                 output.Write(byte(0x15));
                 this.WriteBranchDestination(destination,output)
         | IfNGe(destination) -> 
                 output.Write(byte(0x0f));
                 this.WriteBranchDestination(destination,output)
         | IfNGt(destination) -> 
                output.Write(byte(0x0e));
                this.WriteBranchDestination(destination,output)
         | IfNLe(destination) -> 
                output.Write(byte(0x0d));
                this.WriteBranchDestination(destination,output)
         | IfNLt(destination) -> 
                output.Write(byte(0x0c));
                this.WriteBranchDestination(destination,output)
         | IfNE(destination) -> 
                output.Write(byte(0x14));
                this.WriteBranchDestination(destination,output)
         | IfStrictEq(destination) -> 
                output.Write(byte(0x19));
                this.WriteBranchDestination(destination,output)
         | IfStrictNEq(destination) -> 
                output.Write(byte(0x1a));
                this.WriteBranchDestination(destination,output)
         | IfTrue(destination) -> 
                output.Write(byte(0x11));
                this.WriteBranchDestination(destination,output)
         | In -> output.Write(byte(0xb4));
         | IncLocal(index) -> 
                output.Write(byte(0x92));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | IncLocalI(index) -> 
                output.Write(byte(0xc2));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output);
         | Increment -> output.Write(byte(0x91));
         | IncrementI -> output.Write(byte(0xc0));
         | InitProperty(index) -> 
                output.Write(byte(0x68));
                let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(index)
                   in
                    TypeEncodingUtilities.WriteU30Value(uint32(nameIndex),output);
         | InstanceOf -> output.Write(byte(0xb1));
         | IsType(typeIndex) -> 
                output.Write(byte(0xb2));
                TypeEncodingUtilities.WriteU30Value(uint32(typeIndex),output);
         | IsTypeLate -> output.Write(byte(0xb3));
         | Jump(destination) -> 
              output.Write(byte(0x10));
              this.WriteBranchDestination(destination,output)
                            
         | Kill(index) -> 
              output.Write(byte(0x08));
              TypeEncodingUtilities.WriteU30Value(uint32(index),output)
         | Label -> output.Write(byte(0x09));
         | LessEquals -> output.Write(byte(0xae));
         | LessThan -> output.Write(byte(0xad));
         | LookupSwitch(defaultCase,destinations) ->
              output.Write(byte(0x1b));
              this.WriteBranchDestination(defaultCase,output)
              TypeEncodingUtilities.WriteU30Value(uint32(destinations.Length - 1),output)
              Array.iter(fun v -> this.WriteBranchDestination(v,output)) destinations              
         | LShift -> output.Write(byte(0xa5));
         | Modulo -> output.Write(byte(0xa4));
         | Multiply -> output.Write(byte(0xa2));
         | MultiplyI -> output.Write(byte(0xc7));
         | Negate -> output.Write(byte(0x90));
         | NegateI -> output.Write(byte(0xc4));
         | NewActivation -> output.Write(byte(0x57));
         | NewArray(typeIndex) -> 
                 output.Write(byte(0x56));
                 TypeEncodingUtilities.WriteU30Value(uint32(typeIndex),output)
         | NewCatch(exceptionIndex) -> 
                 output.Write(byte(0x5a));
                 TypeEncodingUtilities.WriteU30Value(uint32(exceptionIndex),output)
         | NewClass(className) ->
                 output.Write(byte(0x58));
                 match fileCreator.GetClassIndexForName(className) with
                 | Some(index) -> TypeEncodingUtilities.WriteU30Value(uint32(index),output)
                 | None -> raise ( new Exception("Trying to write a 'newclass' to a non existing class"))
         | NewFunction(functionIndex) -> 
                 output.Write(byte(0x40));
                 TypeEncodingUtilities.WriteU30Value(uint32(functionIndex),output)
         | NewObject(classIndex) -> 
                 output.Write(byte(0x55));
                 TypeEncodingUtilities.WriteU30Value(uint32(classIndex),output)
         | NextName -> output.Write(byte(0x1e));
         | NextValue -> output.Write(byte(0x23));
         | Nop -> output.Write(byte(0x02));
         | Not -> output.Write(byte(0x96));
         | Pop -> output.Write(byte(0x29));
         | PopScope -> output.Write(byte(0x1d));
         | PushByte(byteValue) -> 
                output.Write(byte(0x24));
                output.Write(byteValue)
         | PushDouble(doubleValue)-> 
                output.Write(byte(0x2f));
                TypeEncodingUtilities.WriteU30Value(uint32(fileCreator.ConstantPoolCreator.GetDoubleIndex(doubleValue)),output)
         | PushFalse -> output.Write(byte(0x27));
         | PushInt(intValue)          -> 
                output.Write(byte(0x2d));
                TypeEncodingUtilities.WriteU30Value(uint32(fileCreator.ConstantPoolCreator.GetIntIndex(intValue)),output)
         | PushNamespace(nsIndex) -> 
                output.Write(byte(0x31));
                TypeEncodingUtilities.WriteU30Value(uint32(nsIndex),output)
         | PushNan -> output.Write(byte(0x28));
         | PushNull -> output.Write(byte(0x20));
         | PushScope -> output.Write(byte(0x30));
         | PushShort(shortIndex) -> 
                output.Write(byte(0x25));
                TypeEncodingUtilities.WriteU30Value(uint32(shortIndex),output)
         | PushString(theString) -> 
                output.Write(byte(0x2c));
                TypeEncodingUtilities.WriteU30Value(uint32(fileCreator.ConstantPoolCreator.AddString(theString)),output)
         | PushTrue -> output.Write(byte(0x26));
         | PushUInt(index) -> 
                output.Write(byte(0x2e));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output)
         | PushUndefined -> output.Write(byte(0x21));
         | PushWith -> output.Write(byte(0x1c));
         | ReturnValue -> output.Write(byte(0x48));
         | ReturnVoid -> output.Write(byte(0x47));
         | RShift -> output.Write(byte(0xa6));
         | SetLocal(localIndex) -> 
                output.Write(byte(0x63));
                TypeEncodingUtilities.WriteU30Value(uint32(localIndex),output)
         | SetLocal_0 -> output.Write(byte(0xd4));
         | SetLocal_1 -> output.Write(byte(0xd5));
         | SetLocal_2 -> output.Write(byte(0xd6));
         | SetLocal_3 -> output.Write(byte(0xd7));
         | SetGlobalSlot(index) ->
                output.Write(byte(0x6f));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output)
         | SetProperty(index) -> 
                output.Write(byte(0x61));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output)
         | SetSlot(index) -> 
                output.Write(byte(0x6d));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output)
         | SetSuper(index) -> 
                output.Write(byte(0x05));
                TypeEncodingUtilities.WriteU30Value(uint32(index),output)
         | StrictEquals -> output.Write(byte(0xac));
         | Subtract -> output.Write(byte(0xa1));
         | SubtractI -> output.Write(byte(0xc6));
         | Swap -> output.Write(byte(0x2b));
         | Throw -> output.Write(byte(0x03));
         | TypeOf -> output.Write(byte(0x95));
         | URShift -> output.Write(byte(0xa7));
//         | u -> raise (new InvalidDataException(String.Format("Unknown instruction {0}",u)))

   member this.WriteBranchDestination(destination,output) =
     (match destination with
               | UnSolvedReference(idestination) -> 
                      TypeEncodingUtilities.WriteS24Value(idestination,output)
               | _ -> raise (new Exception("Could not write solved label")))

               
   member this.Name 
     with get() =
         match this with           
             | ArtificialCodeBranchLabel _ -> "ArtificialJumpLabel"
             | Add -> "add"           
             | AsType(_) -> "astype"
             | AsTypeLate -> "astypelate"
             | BitAnd -> "bitadd"
             | BitNot -> "bitnot"
             | BitOr -> "bitor"
             | BitXor -> "bitxor"
             | Call _ -> "call"
             | CallMethod(_,_) -> "callmethod"
             | CallProperty(_,_) -> "callprop"
             | CallPropLex(_,_) -> "callproplex"
             | CallPropVoid(_,_) -> "callpropvoid"
             | CallStatic(_,_) -> "callstatic"
             | CallSuper(_,_) -> "callsuper"
             | CallSuperVoid(_,_) -> "callsupervoid"
             | CheckFilter -> "checkfilter"
             | Coerce _ -> "coerce"
             | CoerceA -> "coerce_a"
             | CoerceS -> "coerce_s"
             | Construct _ -> "construct"
             | ConstructProp(_,_) -> "constructprop"
             | ConstructSuper _ -> "constructsuper"
             | ConvertB -> "convert_b"
             | ConvertI -> "convert_i"
             | ConvertD -> "convert_d"
             | ConvertO -> "convert_o"
             | ConvertU -> "convert_u"
             | ConvertS -> "convert_s"
             | Debug (_,_,_,_) -> "debug"
             | DebugFile _ -> "debugfile"
             | DebugLine _ -> "debugline"
             | DecLocal _ -> "declocal"
             | DecLocalI _ -> "declocal_i"
             | Decrement -> "decrement"
             | DecrementI  -> "decrement_i"
             | DeleteProperty _ -> "deleteproperty"
             | Divide -> "divide"
             | Dup -> "dup"
             | DXNs _ -> "dxns"
             | DXNslate -> "DXNslate"
             | Equals -> "equals"
             | EscXAttr -> "escxattr"
             | EscXElem -> "escxelem"
             | FindProperty _ -> "findproperty"
             | FindPropertyStrict _ -> "findpropertystrict"
             | GetDescendants _ -> "getdescendants"
             | GetGlobalScope -> "getglobalscope"
             | GetGlobalSlot _ -> "getglobalslot"
             | GetLex _ -> "getlex"
             | GetLocal _ -> "getlocal"
             | GetLocal0 -> "getlocal_0"
             | GetLocal1 -> "getlocal_1"
             | GetLocal2 -> "getlocal_2"
             | GetLocal3 -> "getlocal_3"
             | GetProperty _ -> "getproperty"
             | GetScopeObject _ -> "getscopeobject"
             | GetSlot _ -> "getslot"
             | GetSuper _ -> "getsuper"
             | GreaterEquals -> "greaterequals"
             | GreaterThan -> "greaterthan"
             | HasNext -> "hasnext"
             | HasNext2(_,_) -> "hasnext2"
             | IfEq _ -> "ifeq"
             | IfFalse _ -> "iffalse"
             | IfGe _ -> "ifge"
             | IfGt _ -> "ifgt"
             | IfLe _ -> "ifle"
             | IfLt _ -> "iflt"
             | IfNGe _ -> "ifnge"
             | IfNGt _ -> "ifngt"
             | IfNLe _ -> "ifnle"
             | IfNLt _ -> "ifnlt"
             | IfNE _ -> "ifne"
             | IfStrictEq _ -> "ifstricteq"
             | IfStrictNEq _ -> "ifstrictneq"
             | IfTrue _ -> "iftrue"
             | In -> "in"
             | IncLocal _ -> "inclocal"
             | IncLocalI _ -> "inclocal_i"
             | Increment -> "increment"
             | IncrementI -> "increment_i"
             | InitProperty _ -> "initproperty"
             | InstanceOf -> "instanceof"
             | IsType _ -> "istype"
             | IsTypeLate _ -> "istypelate"
             | Jump _ -> "jump"
             | Kill _ -> "kill"
             | Label -> "label"
             | LessEquals -> "lessequals"
             | LessThan -> "lessthan"
             | LookupSwitch (_,_) -> "lookupswitch"
             | LShift -> "lshift"
             | Modulo -> "modulo"
             | Multiply -> "multiply"
             | MultiplyI -> "multiply_i"
             | Negate -> "negate"
             | NegateI -> "negate_i"
             | NewActivation -> "newactivation"
             | NewArray _ -> "newarray"
             | NewCatch _ -> "newcatch"
             | NewClass _ -> "newclass"
             | NewFunction _ -> "newfunction"
             | NewObject _ -> "newobject"
             | NextName -> "nextname"
             | NextValue -> "nextvalue"
             | Nop -> "nop"
             | Not -> "not"
             | Pop -> "pop"
             | PopScope -> "popscope"
             | PushByte _ -> "pushbyte"
             | PushDouble _ -> "pushdouble"
             | PushFalse -> "pushfalse"
             | PushInt _ -> "pushint"
             | PushNamespace _ -> "pushnamespace"
             | PushNan -> "pushnan"
             | PushNull -> "pushnull"
             | PushScope -> "pushscope"
             | PushShort _ -> "pushshort"
             | PushString _ -> "pushstring"
             | PushTrue -> "pushtrue"
             | PushUInt _ -> "pushuint"
             | PushUndefined -> "pushundefined"
             | PushWith -> "pushwith"
             | ReturnValue -> "returnvalue"
             | ReturnVoid -> "returnvoid"
             | RShift -> "rshift"
             | SetLocal _ -> "setlocal"
             | SetLocal_0 -> "setlocal_0"
             | SetLocal_1 -> "setlocal_1"
             | SetLocal_2 -> "setlocal_2"
             | SetLocal_3 -> "setlocal_3"
             | SetGlobalSlot _ -> "setglobalslot"
             | SetProperty  _ -> "setproperty"
             | SetSlot _ -> "setslot"
             | SetSuper _ -> "setsuper"
             | StrictEquals  -> "strictequals"
             | Subtract -> "subtract"
             | SubtractI -> "subtract_i"
             | Swap -> "swap"
             | Throw -> "throw"
             | TypeOf -> "typeof"
             | URShift -> "urshift"
             
   member this.GetSize(fileCreator:AbcFileCreator) =
         match this with           
             | ArtificialCodeBranchLabel _ -> 0
             | AsType(_) -> 0 + 3
             | Call methodId -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallMethod(index,methodId) -> 
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(index))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallProperty(propertyName,methodId) -> 
                             let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName) in                   
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallPropLex(index,methodId) -> 
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(index))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallPropVoid(name,methodId) -> 
                             let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(name) in                   
                             
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallStatic(index,methodId) -> 
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(index))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallSuper(methodName,methodId) -> 
                          let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(methodName) in                   
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | CallSuperVoid(index,methodId) -> 
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(index))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(methodId))
             | Coerce index -> TypeEncodingUtilities.CalculateU30Size(uint32(index))
             | Construct argcount -> TypeEncodingUtilities.CalculateU30Size(uint32(argcount))
             | ConstructProp(propertyName,argcount) -> 
                        let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName) in
                                1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex))
                                  + TypeEncodingUtilities.CalculateU30Size(uint32(argcount))
             | ConstructSuper argcount -> TypeEncodingUtilities.CalculateU30Size(uint32(argcount))
             | Debug (_,index,_,extra) -> 
                            1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) +
                            1 + TypeEncodingUtilities.CalculateU30Size(uint32(extra))
             | DebugFile index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | DebugLine index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | DecLocal index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | DecLocalI index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | DeleteProperty index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | DXNs index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | FindProperty propertyName -> 
                     let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName)
                     in
                       1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex)) 
             | FindPropertyStrict propertyName -> 
                     let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName)
                     in
                      1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex)) 
             | GetDescendants index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | GetGlobalSlot index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | GetLex name -> 
                    let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(name)
                     in
                       1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex)) 
             | GetLocal index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | GetProperty propertyName -> 
                  let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(propertyName)
                   in
                    1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex)) 
             | GetScopeObject index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | GetSlot index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | GetSuper index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | HasNext2(objreg,indexreg) -> 
                      1 + 
                      TypeEncodingUtilities.CalculateU30Size(uint32(objreg)) +
                      TypeEncodingUtilities.CalculateU30Size(uint32(indexreg))
             | IfEq index -> 1 + 3
             | IfFalse _ -> 1+3
             | IfGe _ -> 1+3
             | IfGt _ -> 1+3
             | IfLe _ -> 1+3
             | IfLt _ -> 1+3
             | IfNGe _ -> 1+3
             | IfNGt _ -> 1+3
             | IfNLe _ -> 1+3
             | IfNLt _ -> 1+3
             | IfNE _ -> 1+3
             | IfStrictEq _ -> 1+3
             | IfStrictNEq _ -> 1+3
             | IfTrue _ -> 1+3
             | IncLocal index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | IncLocalI index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | InitProperty index -> 
                  let nameIndex = fileCreator.ConstantPoolCreator.GetNameEntry(index)
                   in
                   1 + TypeEncodingUtilities.CalculateU30Size(uint32(nameIndex)) 
             | IsType index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | Jump _ -> 1 + 3
             | Kill index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | LookupSwitch (_,cases) -> 
                             1+3+TypeEncodingUtilities.CalculateU30Size(uint32(cases.Length-1)) +
                             cases.Length*3                             
             | NewArray index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | NewCatch index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | NewClass className -> 
                  1 + 
                  (match fileCreator.GetClassIndexForName(className) with
                   | Some(index) -> TypeEncodingUtilities.CalculateU30Size(uint32(index))
                   | None -> raise ( new Exception("Trying to write a 'newclass' to a non existing class")))
                    
             | NewFunction index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | NewObject index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | PushByte _ -> 2
             | PushDouble index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | PushInt index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | PushNamespace index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | PushShort index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | PushString theString -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(fileCreator.ConstantPoolCreator.AddString(theString)))
             | PushUInt index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | SetLocal index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | SetGlobalSlot index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | SetProperty  index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | SetSlot index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | SetSuper index -> 1 + TypeEncodingUtilities.CalculateU30Size(uint32(index)) 
             | _ -> 1 
end



module InstructionUtilities = begin


   let ConvertToByteArray(instructions : AbcFileInstruction array,fileCreator:AbcFileCreator) = 
      let stream = new MemoryStream() in
      let binWriter  = new BinaryWriter(stream) in
        Array.iter (fun (instruction:AbcFileInstruction) -> instruction.WriteTo(binWriter,fileCreator)) instructions ;
        binWriter.Close() ;
        stream.Close() ;
        stream.ToArray() ;
        
        
end

module InstructionPatterns = begin
   
   let (|UnsolvedSingleBranchInstruction|_|)(instruction:AbcFileInstruction) =
            match instruction with
            | IfEq(UnSolvedReference offset) -> Some(offset,fun o -> IfEq(o))
            | IfFalse(UnSolvedReference offset) -> Some(offset,fun o -> IfFalse(o))
            | IfGe(UnSolvedReference offset) -> Some(offset,fun o -> IfGe(o))
            | IfGt(UnSolvedReference offset) -> Some(offset,fun o -> IfGt(o))
            | IfLe(UnSolvedReference offset) -> Some(offset,fun o -> IfLe(o))
            | IfLt(UnSolvedReference offset) -> Some(offset,fun o -> IfLt(o))
            | IfNGe(UnSolvedReference offset) -> Some(offset,fun o -> IfNGe(o))
            | IfNGt(UnSolvedReference offset) -> Some(offset,fun o -> IfNGt(o))
            | IfNLe(UnSolvedReference offset) -> Some(offset,fun o -> IfNLe(o))
            | IfNLt(UnSolvedReference offset) -> Some(offset,fun o -> IfNLt(o))
            | IfNE(UnSolvedReference offset) -> Some(offset,fun o -> IfNE(o))
            | IfStrictEq(UnSolvedReference offset) -> Some(offset,fun o -> IfStrictEq(o))
            | IfStrictNEq(UnSolvedReference offset) -> Some(offset,fun o -> IfStrictNEq(o))
            | IfTrue(UnSolvedReference offset) -> Some(offset,fun o -> IfTrue(o))
            | Jump(UnSolvedReference offset) -> Some(offset,fun o -> Jump(o))
            | _ -> None
            
            
   let (|UnsolvedAbsoluteBranchInstruction|_|)(pair:int64*AbcFileInstruction) =
      let (instructionOffset,instruction) = pair in
      let absoluteOffset(relativeOffset:int) = int64(3 + 1 + relativeOffset) + instructionOffset in
      let result(offset,createFunction) =  Some(absoluteOffset <| offset,createFunction) 
      in
         match instruction with
            | UnsolvedSingleBranchInstruction(offset,f) -> result(offset,f)
            | _ -> None

  
   let (|SolvedSingleBranchInstruction|_|)(instruction:AbcFileInstruction) =
         match instruction with
            | IfEq(SolvedReference label) -> Some(label,fun o -> IfEq(o))
            | IfFalse(SolvedReference label) -> Some(label,fun o -> IfFalse(o))
            | IfGe(SolvedReference label) -> Some(label,fun o -> IfGe(o))
            | IfGt(SolvedReference label) -> Some(label,fun o -> IfGt(o))
            | IfLe(SolvedReference label) -> Some(label,fun o -> IfLe(o))
            | IfLt(SolvedReference label) -> Some(label,fun o -> IfLt(o))
            | IfNGe(SolvedReference label) -> Some(label,fun o -> IfNGe(o))
            | IfNGt(SolvedReference label) -> Some(label,fun o -> IfNGt(o))
            | IfNLe(SolvedReference label) -> Some(label,fun o -> IfNLe(o))
            | IfNLt(SolvedReference label) -> Some(label,fun o -> IfNLt(o))
            | IfNE(SolvedReference label) -> Some(label,fun o -> IfNE(o))
            | IfStrictEq(SolvedReference label) -> Some(label,fun o -> IfStrictEq(o))
            | IfStrictNEq(SolvedReference label) -> Some(label,fun o -> IfStrictNEq(o))
            | IfTrue(SolvedReference label) -> Some(label,fun o -> IfTrue(o))
            | Jump(SolvedReference label) -> Some(label,fun o -> Jump(o))
            | _ -> None

end
